﻿namespace VividKit.PresentationModel.Navigation
{
    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Navigation;

    /// <summary>
    /// Represents a service that provides properties and events to control the navigation of views for view models.
    /// </summary>
    public static class NavigatorService
    {
        internal static INavigationService NavigationService { get; private set; }

        #region IsNavigationHost (Attached DependencyProperty)

        /// <summary>
        /// Identifies the IsNavigationHost attached property.
        /// </summary>
        public static readonly DependencyProperty IsNavigationHostProperty =
            DependencyProperty.RegisterAttached("IsNavigationHost", typeof(bool),
                typeof(NavigatorService), new PropertyMetadata(HandleIsNavigationHostPropertyChanged));

        /// <summary>
        /// Gets the value of the IsNavigationHost property of the specified object.
        /// </summary>
        /// <param name="o">Object to query concerning the IsNavigationHost property.</param>
        /// <returns>Value of the IsNavigationHost property.</returns>
        public static bool GetIsNavigationHost(DependencyObject o)
        {
            return (bool)o.GetValue(IsNavigationHostProperty);
        }

        /// <summary>
        /// Sets the value of the IsNavigationHost property of the specified object.
        /// </summary>
        /// <param name="o">Object to set the property on.</param>
        /// <param name="value">Value to set.</param>
        public static void SetIsNavigationHost(DependencyObject o, bool value)
        {
            o.SetValue(IsNavigationHostProperty, value);
        }

        private static bool EnableNavigation(FrameworkElement element)
        {
            var service = GetNavigationService(element);
            if (service != null)
            {
                NavigatorService.NavigationService = new DesktopNavigationService(service);
                return true;
            }

            return false;
        }

        private static NavigationService GetNavigationService(FrameworkElement element)
        {
            var page = element as Page;
            if (page != null)
            {
                return page.NavigationService;
            }

            var frame = element as Frame;
            if (frame != null)
            {
                return frame.NavigationService;
            }

            var window = element as NavigationWindow;
            if (window != null)
            {
                return window.NavigationService;
            }

            return null;
        }

        private static void HandleElementLoaded(object sender, RoutedEventArgs e)
        {
            var element = (FrameworkElement)sender;
            element.Loaded -= HandleElementLoaded;

            EnableNavigation(element);
        }

        /// <summary>
        /// Handles changes to the IsNavigationHost DependencyProperty.
        /// </summary>
        /// <param name="d"><see cref="System.Windows.DependencyObject"/> that changed.</param>
        /// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void HandleIsNavigationHostPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var element = d as FrameworkElement;
            var elementIsNavigationHost = e.NewValue != null ? (bool)e.NewValue : false;

            if (elementIsNavigationHost && element != null)
            {
                if (EnableNavigation(element) == false)
                {
                    element.Loaded += HandleElementLoaded;
                }
            }
        }

        #endregion IsNavigationHost (Attached DependencyProperty)
    }
}